package com.jinhua.huaojbackendjudgeservice.judge.judge_service.impl;

import cn.hutool.json.JSONUtil;
import com.jinhua.huaojbackendcommon.common.ErrorCode;
import com.jinhua.huaojbackendcommon.exception.BusinessException;
import com.jinhua.huaojbackendcommon.exception.ThrowUtils;
import com.jinhua.huaojbackendjudgeservice.judge.JudgeManager;
import com.jinhua.huaojbackendjudgeservice.judge.codesandbox.CodeSandBox;
import com.jinhua.huaojbackendjudgeservice.judge.codesandbox.CodeSandBoxFactory;
import com.jinhua.huaojbackendjudgeservice.judge.codesandbox.CodeSandBoxProxy;
import com.jinhua.huaojbackendjudgeservice.judge.judge_service.JudgeService;
import com.jinhua.huaojbackendmodel.model.codesandbox.ExecuteCodeRequest;
import com.jinhua.huaojbackendmodel.model.codesandbox.ExecuteCodeResponse;
import com.jinhua.huaojbackendmodel.model.codesandbox.JudgeInfo;
import com.jinhua.huaojbackendmodel.model.entity.JudgeCase;
import com.jinhua.huaojbackendmodel.model.entity.JudgeContext;
import com.jinhua.huaojbackendmodel.model.entity.Question;
import com.jinhua.huaojbackendmodel.model.entity.QuestionSubmit;
import com.jinhua.huaojbackendmodel.model.enums.QuestionSubmitStateEnum;
import com.jinhua.huaojbackendmodel.model.vo.QuestionView;
import com.jinhua.huaojbackendserviceclient.service.QuestionFeignClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class JudgeServiceImpl implements JudgeService {
    @Resource
    private QuestionFeignClient questionFeignClient;

    @Value("${codesandbox.type:example}")
    private String codesandboxType;

    @Resource
    private JudgeManager judgeManager;

    @Override
    public QuestionSubmit submit(long questionSubmitId) {
//      执行代码 获取需要执行的代码 语言 输入用例    获取输出

        //1、根据传入的题目提交id获取题目判题示例，提交信息（代码，使用语言和输入用例等）
        if (questionSubmitId < 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        QuestionSubmit questionSubmit = questionFeignClient.getQuestionSubmitById(questionSubmitId);
        if(questionSubmit == null){
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "提交信息不存在");
        }
        String language = questionSubmit.getLanguage();
        String code = questionSubmit.getCode();
        Long questionId = questionSubmit.getQuestionId();

        Question question = questionFeignClient.getQuestionById(questionId);
        if (question ==  null){
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "题目不存在");
        }
//      获取QuestionView类将json字符串转换为对应类
        QuestionView questionView = questionFeignClient.getQuestionView(question);
        List<JudgeCase> judgeCase = questionView.getJudgeCase();
//        从判题用例中获取输入列表和输出列表
        List<String> expectInputList = judgeCase.stream().map(JudgeCase::getInput).collect(Collectors.toList());

        List<String> expectOutputList = judgeCase.stream().map(JudgeCase::getOutput).collect(Collectors.toList());

        //2、查看题目提交状态是否符合如果符合更改题目提交状态为判题中
        Integer state = questionSubmit.getState();
        if (state == null || !state.equals(QuestionSubmitStateEnum.WAITING.getValue())){
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "题目正在判题中");
        }

        //更改题目提交的判题状态为判题中  防止重复提交
        QuestionSubmit questionSubmitUpdate = new QuestionSubmit();
        questionSubmitUpdate.setId(questionSubmitId);
        questionSubmitUpdate.setState(QuestionSubmitStateEnum.COMPILING.getValue());
        boolean b = questionFeignClient.updateQuestionSubmitById(questionSubmitUpdate);
        ThrowUtils.throwIf(!b, ErrorCode.SYSTEM_ERROR);


        //3、调用代码沙箱执行执行代码、获取执行结果
        CodeSandBox codeSandBox = new CodeSandBoxProxy(CodeSandBoxFactory.newInstance(codesandboxType));
        ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest
                .builder()
                .code(code)
                .language(language)
                .inputList(expectInputList)
                .build();
        ExecuteCodeResponse executeCodeResponse = codeSandBox.excuteCode(executeCodeRequest);
        if (executeCodeResponse == null){
            throw new BusinessException(ErrorCode.API_REQUEST_ERROR);
        }

        //4、检查执行结果（答案长度、每个答案是否正确并设置judgeInfo的message字段）
        JudgeContext judgeContext = new JudgeContext();
        judgeContext.setJudgeInfo(executeCodeResponse.getExcuteInfo());
        judgeContext.setExcuteOutputList(executeCodeResponse.getOutputList());
        judgeContext.setExpectOutputList(expectOutputList);
        judgeContext.setJudgeConfig(questionView.getJudgeConfig());
        judgeContext.setLanguage(language);

        JudgeInfo judgeInfo = judgeManager.doJudge(judgeContext);

        // 根据执行结果返回设置题目的状态和信息
        questionSubmitUpdate.setState(QuestionSubmitStateEnum.ACCOMPLISH.getValue());
        questionSubmitUpdate.setJudgeInfo(JSONUtil.toJsonStr(judgeInfo));

        boolean update = questionFeignClient.updateQuestionSubmitById(questionSubmitUpdate);
        ThrowUtils.throwIf(!update, ErrorCode.SYSTEM_ERROR);

        return questionFeignClient.getQuestionSubmitById(questionSubmitUpdate.getId());
    }
}
